package com.xt.base.xml;

import java.io.File;
import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

abstract public class XMLBasedService implements InitializingBean {

	static private final String publicFlex = "-//e1Soft//DTD",systemFlex = "http://www.e1soft.com.cn/dtd/";
	
	
	private boolean flushMode = false;

	private Resource resource;

	private long resourceVersion = -1;
	
	private boolean validate;

	private SAXReader reader = new SAXReader();
	
	private EntityResolver entityResolver = new EntityResolver() {
		public InputSource resolveEntity(String publicId,
				String systemId) throws SAXException, IOException {
			if ((!StringUtils.isEmpty(publicId) && publicId
					.indexOf(publicFlex) == 0)
					|| (!StringUtils.isEmpty(systemId) && systemId
							.indexOf(systemFlex) == 0)) {
				Resource resource = new ClassPathResource(getDTDName(),XMLBasedService.this.getClass());
				return new InputSource(resource.getInputStream());
			} else
				return null;
		}
	};
	
	synchronized protected File getFile() throws IOException {
		File file = resource.exists() ? resource.getFile() : null;
		File res = file != null
				&& (resourceVersion < 0 || (flushMode && file.lastModified() != resourceVersion)) ? file
				: null;
		if (res != null)
			resourceVersion = res.lastModified();
		return res;
	}

	protected void parse() throws IOException, DocumentException {
		File file = getFile();
		if (file != null && file.isFile()) {
			Document document = reader.read(file);
			Element root = document != null ? document.getRootElement() : null;
			if (root != null) {
				parse(root);
				log.debug("XMLService initialized:" + resource.getFile()
						+ ",version:" + resourceVersion);
			}
		}
	}

	protected abstract void parse(Element root) throws IOException;

	protected abstract String getDTDName();

	public void afterPropertiesSet() throws Exception {
		reader.setValidation(validate);
		reader.setEntityResolver(entityResolver);
		parse();
		if(!flushMode)reader = null;
	}

	public void setResource(Resource resource) {
		this.resource = resource;
	}

	public void setFlushMode(boolean mode) {
		this.flushMode = mode;
	}

	public void setValidate(boolean validate) {
		this.validate = validate;
	}

	protected static final org.apache.log4j.Logger log = org.apache.log4j.Logger
			.getLogger(XMLBasedService.class);
}
